package com.wyz.socket.core.base;


import com.wyz.socket.core.impl.ConnectorHandler;

public abstract class Chain<Model> {
    private volatile Chain<Model> next;

    public Chain<Model> addChain(Chain<Model> chain) {
        if (this == chain || this.getClass().equals(chain.getClass())) {
            return this;
        }
        synchronized (this) {
            if (next == null) {
                next = chain;
            } else {
                return next.addChain(chain);
            }
            return chain;
        }
    }

    public Chain<Model> addNextChain(Chain<Model> chain) {
        if (this == chain || this.getClass().equals(chain.getClass())) {
            return this;
        }
        synchronized (this) {
            if (next == null) {
                next = chain;
                return chain;
            } else {
                Chain<Model> temp = this.next;
                this.next = chain;
                chain.next = temp;
                return temp;
            }
        }
    }

    public synchronized boolean remove(Class<? extends Chain<Model>> clx) {
        if (this.getClass().equals(clx)) {
            return false;
        }
        synchronized (this) {
            if (next == null) {
                return false;
            } else if (next.getClass().equals(clx)) {
                this.next = this.next.next;
                return true;
            } else {
                return this.next.remove(clx);
            }
        }
    }


    public synchronized boolean handle(ConnectorHandler handler, Model model) {
        Chain<Model> next = this.next;
        if (consume(handler, model)) {
            return true;
        }
        boolean nextConsume = next != null && next.consume(handler, model);
        if (nextConsume) {
            return true;
        }
        return consumeAgain(handler, model);
    }

    protected abstract boolean consume(ConnectorHandler handler, Model model);

    protected boolean consumeAgain(ConnectorHandler handler, Model model) {
        return false;
    }
}
